package sessionbeans;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;


import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;

import dtofactory.FactoryDTO;

import entities.CantidadArticulo;
import entities.CantidadMateriaPrima;
import entities.CentroDeDistribucion;
import entities.PedidoFabricacion;
import entities.PedidoProveedores;
import entities.SolicitudFabricacion;
import entities.Articulo;
import entities.StockMateriaPrima;
import entitiesdto.CantidadArticuloDTO;
import entitiesdto.PedidoFabricacionDTO;
import entitiesdto.PedidoProveedoresDTO;
import entitiesdto.SolicitudFabricacionDTO;
import sessionbeans.AdminFabricacion;

public @Stateless
class AdminFabricacionBean implements AdminFabricacion {

	@PersistenceContext
	private EntityManager manager;
	private FactoryDTO dtoFactory;

	public AdminFabricacionBean() {
		dtoFactory = FactoryDTO.getInstance();
	}

	public boolean crearPedidoFabricacion(SolicitudFabricacionDTO solFabr) {
		// PRIMERO GUARDAR LA SOLICITUD DE FABRICACION
		SolicitudFabricacion sol = new SolicitudFabricacion();
		sol = dtoFactory.solFromDTO(solFabr);
		manager.persist(sol);

		// LUEGO, BUSCAR SI YA EXISTE PEDIDO DE FABRICACION PARA ESE ARTICULO,
		// SI EXISTE, SE AGREGA CANTIDAD AL PEDIDO, SI NO EXISTE, SE CREA UN
		// PEDIDO DE FABRICACION

		for (CantidadArticuloDTO art : solFabr.getArticulos()) {
			PedidoFabricacion pf = (PedidoFabricacion) manager
			.createQuery(
			"select pf from pedidosdefabricacion pf where pf.articulo_ref=: arti")
			.setParameter("arti",
					dtoFactory.dtoToArt(art.getArticulo()))
					.getSingleResult();
			if (pf != null) {
				pf.setCantidadSolicitada(pf.getCantidadSolicitada()
						+ art.getCantidadPedida());
				manager.persist(pf);
			} else {
				pf = new PedidoFabricacion();
				pf.setArticulo(dtoFactory.dtoToArt(art.getArticulo()));
				pf.setCantidadFabricada(0);
				pf.setCantidadSolicitada(art.getCantidadPedida());
				manager.merge(pf);
			}
		}
		return true;
	}

	@SuppressWarnings("unchecked")
	public List<CantidadArticuloDTO> getArticulosSolicitados() {
		List<CantidadArticulo> artsol = manager.createQuery("Select a from CantidadArticulo a").getResultList();
		ArrayList<CantidadArticuloDTO> result = new ArrayList<CantidadArticuloDTO>();
		for (CantidadArticulo as : artsol) {
			CantidadArticuloDTO asDTO = FactoryDTO.getInstance().asolToDTO(as);

			result.add(asDTO);
		}
		return result;
	}

//	@SuppressWarnings("unchecked")
//	public void comenzarFabricacion() {
//		List<PedidoFabricacion> pedidosFab = manager.createQuery("Select p from PedidoFabricacion p").getResultList();
//		PedidoProveedores pProv = new PedidoProveedores();
//		List<CantidadMateriaPrima> pedido = new Vector<CantidadMateriaPrima>();
//		for (PedidoFabricacion pf : pedidosFab) {
//			boolean suf = true;
//			int cantidadAFabricar = pf.getCantidadSolicitada()- pf.getCantidadFabricada();
//			int disponiblesFabricar = cantidadAFabricar;
//			for (CantidadMateriaPrima cmp : pf.getArticulo()
//					.getCantidadMateriasPrimas()) {
//				StockMateriaPrima smp = (StockMateriaPrima) manager.createQuery("Select m from StockMateriaPrima m where m.materiaPrima?=1")
//						.setParameter("1", cmp.getMateriaPrima())
//						.getSingleResult();
//				if ((cmp.getCantidad() * cantidadAFabricar) > smp.getCantidad()) {
//					CantidadMateriaPrima aPedir = new CantidadMateriaPrima();
//					aPedir.setMateriaPrima(cmp.getMateriaPrima());
//					aPedir.setCantidad((cmp.getCantidad() * cantidadAFabricar)- smp.getCantidad());
//					List<CantidadMateriaPrima> materias = pProv
//							.getMateriaPrimaPedida();
//					materias.add(aPedir);
//					pProv.setMateriaPrimaPedida(materias);
//					int posiblesFabricar = (int) (smp.getCantidad()/cmp.getCantidad());
//					if (posiblesFabricar < cantidadAFabricar) {
//						cantidadAFabricar = posiblesFabricar;
//					}
//					suf = false;
//				}
//			}
//			// SI ACA SUF=TRUE quiere decir que tiene la cantidad de materia
//			// prima necesaria
//			if (suf) {
//				// ActualizarStockMateriaPrima
//				for (CantidadMateriaPrima cmp : pf.getArticulo()
//						.getCantidadMateriasPrimas()) {
//					StockMateriaPrima m = (StockMateriaPrima) manager
//							.createQuery(
//									"Select m from StockMateriaPrima m where m.materiaPrima?=1")
//							.setParameter("1", cmp.getMateriaPrima())
//							.getSingleResult();
//					m.setCantidad(m.getCantidad() - cmp.getCantidad()*cantidadAFabricar);
//					pf.setCantidadFabricada(cantidadAFabricar);
//					manager.persist(m);
//					manager.persist(pf);
//			}
//			} else {
//				if (cantidadAFabricar > 0) {
//					for (CantidadMateriaPrima cmp : pf.getArticulo()
//							.getCantidadMateriasPrimas()) {
//						for (CantidadMateriaPrima pedi : pProv.getMateriaPrimaPedida()) {
//							if (pedi.getMateriaPrima() == cmp.getMateriaPrima()) {
//								pedi.setCantidad(pedi.getCantidad()
//												- (cmp.getCantidad() * cantidadAFabricar));
//								StockMateriaPrima smp = (StockMateriaPrima) manager
//										.createQuery(
//												"Select m from StockMateriaPrima m where m.materiaPrima=: mat")
//										.setParameter("mat",
//												cmp.getMateriaPrima())
//										.getSingleResult();// ACA VERIFICAR
//								// MATERIAS PRIMAS
//								// ---- CON FACADE?
//
//								// smp.setCantidad(smp.getCantidad() -
//								// (cmp.getCantidad()*cantidadAFabricar));
//
//								// pedido.setCantidad(pedido.getCantidad() -
//								// smp.getCantidad());
//
//								manager.persist(smp);
//							}
//						}
//					}
//				}
//				manager.persist(pProv);
//			}
//
//		}
//		List<PedidoFabricacion> pedidosFab = manager.createQuery(
//				"Select p from PedidoFabricacion p").getResultList();
//		PedidoProveedores pProv = new PedidoProveedores();
//		for (PedidoFabricacion pf : pedidosFab) {
//			boolean suf = true;
//			int cantidadAFabricar = pf.getCantidadSolicitada()
//					- pf.getCantidadFabricada();
//			int disponiblesFabricar = cantidadAFabricar;
//			for (CantidadMateriaPrima cmp : pf.getArticulo()
//					.getCantidadMateriasPrimas()) {
//
//				StockMateriaPrima smp = (StockMateriaPrima) manager
//						.createQuery(
//								"Select m from StockMateriaPrima m where m.materiaPrima=: mat")
//						.setParameter("mat", cmp.getMateriaPrima())
//						.getSingleResult();// LLAMAR A FACADE?
//				if ((cmp.getCantidad() * cantidadAFabricar) > smp.getCantMateriaPrima().getCantidad()) {
//					CantidadMateriaPrima aPedir = new CantidadMateriaPrima();
//					aPedir.setMateriaPrima(cmp.getMateriaPrima());
//					aPedir.setCantidad((cmp.getCantidad() * cantidadAFabricar)- smp.getCantMateriaPrima().getCantidad());
//					List<CantidadMateriaPrima> materias = pProv
//							.getMateriaPrimaPedida();
//					materias.add(aPedir);
//					pProv.setMateriaPrimaPedida(materias);
//					int posiblesFabricar = (int) (smp.getCantMateriaPrima().getCantidad() * cmp.getCantidad());
//					if (posiblesFabricar < cantidadAFabricar) {
//						cantidadAFabricar = posiblesFabricar;
//					}
//					suf = false;
//				}
//			}
//			// SI ACA SUF=TRUE quiere decir que tiene la cantidad de materia
//			// prima necesaria
//			if (suf) {
//				// ActualizarStockMateriaPrima FACADE?
//				for (CantidadMateriaPrima cmp : pf.getArticulo()
//						.getCantidadMateriasPrimas()) {
//					StockMateriaPrima m = (StockMateriaPrima) manager
//							.createQuery(
//									"Select m from StockMateriaPrima m where m.materiaPrima=: mat")
//							.setParameter("mat", cmp.getMateriaPrima())
//							.getSingleResult();// ACA VERIFICAR MATERIAS PRIMAS
//					// // ---- CON FACADE?
//
//					// m.setCantidad(m.getCantMateriaPrima().getCantidad()
//					// - (cmp.getCantidad() * cantidadAFabricar));
//					// manager.persist(m);
//
//					// //ACA HAY QUE PONER QUE ESTAN EN PROCESO DE FABRICACION
//				}
//			} else {
//				if (cantidadAFabricar > 0) {
//					for (CantidadMateriaPrima cmp : pf.getArticulo()
//							.getCantidadMateriasPrimas()) {
//						for (CantidadMateriaPrima pedido : pProv
//								.getMateriaPrimaPedida()) {
//							if (pedido.getMateriaPrima() == cmp
//									.getMateriaPrima()) {
//								pedido
//										.setCantidad(pedido.getCantidad()
//												- (cmp.getCantidad() * cantidadAFabricar));
//								StockMateriaPrima smp = (StockMateriaPrima) manager
//										.createQuery(
//												"Select m from StockMateriaPrima m where m.materiaPrima=: mat")
//										.setParameter("mat",
//												cmp.getMateriaPrima())
//										.getSingleResult();// ACA VERIFICAR
//								// MATERIAS PRIMAS
//								// ---- CON FACADE?
//
//								// smp.setCantidad(smp.getCantidad() -
//								// (cmp.getCantidad()*cantidadAFabricar));
//
//								// pedido.setCantidad(pedido.getCantidad() -
//								// smp.getCantidad());
//
//								manager.persist(smp);
//							}
//						}
//					}
//				}
//				manager.persist(pProv);
//			}
//
//		}
//	}
	 
	public List<CantidadArticulo> cantidadArticulos(List <CantidadArticuloDTO> cantidad){
		List<CantidadArticulo> artics = new Vector<CantidadArticulo>();
		for(CantidadArticuloDTO c: cantidad){
			CantidadArticulo cart = new CantidadArticulo(); 
			cart.setCantidadPedida(c.getCantidadPedida());
			Articulo art = manager.find(Articulo.class, c.getArticulo().getRef());
			cart.setArticulo(art);
			artics.add(cart);
		}
		return artics;
	}

	public boolean crearSolicitudFabricacion(SolicitudFabricacionDTO solFabr) {
		// PRIMERO GUARDAR LA SOLICITUD DE FABRICACION
		SolicitudFabricacion sol = new SolicitudFabricacion();
		sol = dtoFactory.solFromDTO(solFabr);
		sol.setArticulos(cantidadArticulos(solFabr.getArticulos()));
		sol.setCD(getCentroDistr(solFabr.getReferenciaCD().getId()));
		manager.persist(sol);

		// LUEGO, BUSCAR SI YA EXISTE PEDIDO DE FABRICACION PARA ESE ARTICULO,
		// SI EXISTE, SE AGREGA CANTIDAD AL PEDIDO, SI NO EXISTE, SE CREA UN
		// PEDIDO DE FABRICACION

		for (CantidadArticulo art : sol.getArticulos()) {
			Articulo arti = art.getArticulo();
			PedidoFabricacion pf; 
			try{
				pf = (PedidoFabricacion) manager
				.createQuery(
				"select pf from PedidoFabricacion pf where pf.articulo=?1")
				.setParameter("1",arti)
				.getSingleResult();     
				pf.setCantidadSolicitada(pf.getCantidadSolicitada()
				+ art.getCantidadPedida());
				manager.merge(pf);

			}catch (NoResultException e) {
				pf = new PedidoFabricacion();
				pf.setArticulo(arti);
				pf.setCantidadFabricada(0);
				pf.setCantidadSolicitada(art.getCantidadPedida());
				manager.persist(pf);
			}
		}
		return true;
	}

//	public void comenzarFabricacion()
//	{
//		List <CantidadMateriaPrima> pedidoProveedores = new ArrayList<CantidadMateriaPrima>();
//		List<SolicitudFabricacion> solicitudesFab = manager.createQuery("select s from solicitudfabricacion s").getResultList();
//
//		for (SolicitudFabricacion solfab : solicitudesFab) {
//			List<CantidadArticulo> cantArtList = solfab.getArticulos();
//			for (CantidadArticulo cantArt : cantArtList) {
//				Articulo art = cantArt.getArticulo();
//				int cant = cantArt.getCantidadPedida();
//				List<CantidadMateriaPrima> cmpList = art.getCantidadMateriasPrimas();
//
//				List<StockMateriaPrima> stock = manager.createQuery("select st from stockmateriaprima st").getResultList();
//
//				// verificar cuantas unidades de art se pueden fabricar
//				int maxFab=cant;
//				for (CantidadMateriaPrima cmp : cmpList) {
//					for (StockMateriaPrima smp : stock){
//						if (cmp.getMateriaPrima().getRef().equals(smp.getMateriaPrima().getRef())){
//							int cantAux = (int) (smp.getCantidad()/cmp.getCantidad());
//							if(cantAux<maxFab){
//								maxFab=cantAux;
//							}
//						}
//					}
//				}
//
//				if(maxFab!=0){
//					// verificar si ya existe un pedido para este articulo
//					PedidoFabricacion pf = null;
//					pf = getPedidoByArticulo(art);
//					if (pf!=null){
//						pf.setCantidadSolicitada(pf.getCantidadSolicitada()+maxFab);
//						manager.merge(pf); // actualizar
//					} else{// si no existe, crear nuevo pedido
//						pf = new PedidoFabricacion(art, maxFab,0);
//						manager.persist(pf);
//					}
//
//					// actualizar stock de materias primas
//					for (CantidadMateriaPrima cmp : cmpList) {
//						for (StockMateriaPrima smp : stock){
//							if (cmp.getMateriaPrima().getRef().equals(smp.getMateriaPrima().getRef())){
//								smp.setCantidad(smp.getCantidad()-maxFab*cmp.getCantidad());
//								manager.merge(smp); // actualizo
//							}
//						}
//					}
//				} 
//				
//				// generar pedido de materias primas faltantes para proveedores
//				int cantInc = cant-maxFab;
//				if(cantInc!=0){
//					
//				}
//			}// fin de revisar el articulo
//		}
//	}

	public StockMateriaPrima getMateriaPrimaByRef(String ref) {
		StockMateriaPrima mp = manager.find(StockMateriaPrima.class, ref);
		return mp;
	}

	@SuppressWarnings("unused")
	private PedidoFabricacion getPedidoByArticulo(Articulo art){
		PedidoFabricacion pf = null;
		pf = (PedidoFabricacion) manager.createQuery("select pf from PedidoFabricacion pf where pf.articulo=:arti").setParameter("arti",art).getSingleResult();   
		return pf;
	}
	
	@SuppressWarnings("unchecked")
	public List<PedidoFabricacionDTO> getPedidosFabricacion(){
		List<PedidoFabricacion> pedidos = manager.createQuery("select pf from pedidosdefabricacion pf").getResultList();
		List<PedidoFabricacionDTO> pedidosDto = FactoryDTO.getInstance().pedFabToDTO(pedidos);
		return pedidosDto;
	}
	
	public CentroDeDistribucion getCentroDistr(int id){
		CentroDeDistribucion cd = manager.find(CentroDeDistribucion.class, id);
		if(cd==null){
			cd=new CentroDeDistribucion();
			cd.setId(id);
			cd.setName("Centro numero" + id);
			manager.persist(cd);
		}
		return cd;
	}

	@SuppressWarnings("unchecked")
	public List<PedidoProveedoresDTO> getPedidosProveedores() {
		List<PedidoProveedores> pf = manager.createQuery("select pp from PedidoProveedores pp").getResultList();
		List<PedidoProveedoresDTO> result = new ArrayList<PedidoProveedoresDTO>();
		for(PedidoProveedores pedidoProov : pf){
			PedidoProveedoresDTO ped = FactoryDTO.getInstance().pedProovToDto(pedidoProov);
			result.add(ped);
		}
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public PedidoProveedoresDTO comenzarFabricacion() 
	{
		List<PedidoFabricacion> pedidosFab = manager.createQuery("Select p from PedidoFabricacion p").getResultList();
		List<StockMateriaPrima> listaStock = manager.createQuery("select st from StockMateriaPrima st").getResultList();
		List<CantidadMateriaPrima> pedidosTemp = new ArrayList<CantidadMateriaPrima>();
		PedidoProveedores pedidoProovedores = new PedidoProveedores();
		
		for (PedidoFabricacion pedidoAux : pedidosFab) {
			List<CantidadMateriaPrima> listaMateriasNec = pedidoAux.getArticulo().getCantidadMateriasPrimas();
			int cantPedida = pedidoAux.getCantidadSolicitada();
			
			// verificar cuantas unidades del articulo se pueden fabricar
			int maxFab=cantPedida;
			for (CantidadMateriaPrima cmp : listaMateriasNec) {
				for (StockMateriaPrima smp : listaStock){
					if (cmp.getMateriaPrima().getRef().equals(smp.getMateriaPrima().getRef())){
						int cantAux = (int) (smp.getCantidad()/cmp.getCantidad());
						if(cantAux<maxFab){
							maxFab=cantAux;
						}
					}
				}
			}
			
			if (maxFab!=0){
				pedidoAux.setCantidadFabricada(maxFab);
				manager.merge(pedidoAux);
			}
			
			// actualizar stock de materias primas
			for (CantidadMateriaPrima cmp : listaMateriasNec) {
				for (StockMateriaPrima smp : listaStock){
					if (cmp.getMateriaPrima().getRef().equals(smp.getMateriaPrima().getRef())){
						smp.setCantidad(smp.getCantidad()-maxFab*cmp.getCantidad());
						manager.merge(smp); // actualizo
						
						// generar pedido de materias primas faltantes para proveedores
						int cantInc = (int) ((cantPedida-maxFab)* cmp.getCantidad());
						if(cantInc!=0){
							CantidadMateriaPrima auxPedido = new CantidadMateriaPrima();
							auxPedido.setMateriaPrima(cmp.getMateriaPrima());
							auxPedido.setCantidad(cantInc);
							pedidosTemp.add(auxPedido);
						}
					}
				}
			}
		}
		
		pedidoProovedores.setMateriaPrimaPedida(pedidosTemp);
		
		// si hay alguna materia prima que pedi, la guardo
		if (pedidoProovedores.getMateriaPrimaPedida().size()>0){
			manager.persist(pedidoProovedores);
//			manager.flush();
		}
		
		return FactoryDTO.getInstance().pedProovToDto(pedidoProovedores);
	}
}
